
// INCLUDES ********************************************************************

#include "DrawableContainer.h"

#include "Drawable.h"

#include "TextureCache.h"

#include "Texture2D.h"

// NAMESPACES ******************************************************************

#pragma mark -
#pragma mark Constructor
// -----------------------------------------------------------------------------

Meteor::DrawableContainer::DrawableContainer( const Meteor::Vector2D size)

: Drawable(), mSize( size)
{
}

// -----------------------------------------------------------------------------

Meteor::DrawableContainer::DrawableContainer( const uint32_t zIndex,
                                              const Meteor::Vector2D size)

: Drawable( zIndex), mSize( size)
{
}


#pragma mark -
#pragma mark Destructor
// -----------------------------------------------------------------------------

Meteor::DrawableContainer::~DrawableContainer()
{
    containerType::iterator iter = mChildren.begin();
    
    while ( iter != mChildren.end())
    {
        const bool erase = ( *iter).second;
    
        if ( erase == true)
        {
            delete ( *iter).first;
        }
        
        iter = mChildren.erase( iter);
    }
}


#pragma mark -
#pragma mark Child management
// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::AddChild( Drawable* child,
                                          const bool takeOwnership)
{
    if ( child == nullptr)
    {
        Logger::Error( "DrawableContainer::AddChild - Child may not be null");
    }

    if ( child->Parent() == this)
    {
        Logger::Error( "DrawableContainer::AddChild - child already added");
    
        return;
    }
    else if ( child->Parent() != 0)
    {
        Logger::Error( "DrawableContainer::AddChild - \
child already added to another container.");
    
        return;
    }
    
    child->SetParent( this);
    
    std::pair<Drawable*, const bool> mNewEntry( child, takeOwnership);
    
    mChildren.push_back( mNewEntry);
    
    std::sort( mChildren.begin(), mChildren.end(), DepthComparator());
}

// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::RemoveChild( Meteor::Drawable* child)
{
    containerType::iterator iter = mChildren.begin();
    
    while ( iter != mChildren.end())
    {
        if ( ( *iter).first == child)
        {
            ( *iter).first->SetParent( 0);
        
            if( ( *iter).second == true)
            {
                delete ( *iter).first;
            }
            
            mChildren.erase( iter);
            
            return;
        }
        
        iter++;
    }
}

// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::Clear()
{
    containerType::iterator iter = mChildren.begin();
    
    while ( iter != mChildren.end())
    {
        if( ( *iter).second == true)
        {
            delete ( *iter).first;
        }
    
        mChildren.erase( iter);
     
        iter++;
    }
}

#pragma mark -
#pragma mark Position
// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::SetPosition( const float x, const float y)
{
    float deltaX = x - mPosition.X();
    
    float deltaY = y - mPosition.Y();
    
    containerType::iterator iter = mChildren.begin();
    
    while ( iter != mChildren.end())
    {
        ( *iter).first->MoveBy( deltaX, deltaY);
        
        iter++;
    }

    mPosition.SetX( x);
    
    mPosition.SetY( y);
}

// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::SetPosition( const Meteor::Vector2D& newPosition)
{
    if ( mPosition == newPosition )
    {
        return;
    }
    
    const float deltaX = newPosition.X() - mPosition.X();
    
    const float deltaY = newPosition.Y() - mPosition.Y();
    
    containerType::iterator iter = mChildren.begin();
    
    while ( iter != mChildren.end())
    {
        ( *iter).first->MoveBy( deltaX, deltaY);
        
        iter++;
    }
    
    mPosition = newPosition;
}


#pragma mark -
#pragma mark Size
// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::SetSize( const Meteor::Vector2D& size)
{
    mSize = size;
}

// -----------------------------------------------------------------------------

const Meteor::Vector2D& Meteor::DrawableContainer::Size() const
{
    return mSize;
}

#pragma mark -
#pragma mark Scale
// -----------------------------------------------------------------------------

const float Meteor::DrawableContainer::Scale() const
{
    return mScale;
}

// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::SetScale( const float newScale)
{
    mScale = newScale;
    
    if ( mScale < 0.0f)
    {
        mScale = 0.0f;
    }
    
    containerType::iterator iter = mChildren.begin();
    
    while ( iter != mChildren.end())
    {
        ( *iter).first->SetScale( mScale);
        
        iter++;
    }
}


#pragma mark -
#pragma mark Rotation
// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::SetRotation( const float angle)
{
    mRotation = angle;
    
    if ( mRotation > 360.0f)
    {
        mRotation = 0.0f;
    }
    
    containerType::iterator iter = mChildren.begin();
    
    while ( iter != mChildren.end())
    {
        ( *iter).first->SetRotation( mRotation);
        
        iter++;
    }
}

// -----------------------------------------------------------------------------

const float Meteor::DrawableContainer::Rotation() const
{
    return mRotation;
}


#pragma mark -
#pragma mark Alpha
// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::SetAlpha( const float alpha)
{
    mAlpha = alpha;
    
    if ( mAlpha > 1.0f)
    {
        mAlpha = 1.0f;
    }
    
    if ( mAlpha < 0.0f)
    {
        mAlpha = 0.0f;
    }
    
    containerType::iterator iter = mChildren.begin();
    
    while ( iter != mChildren.end())
    {
        ( *iter).first->SetAlpha( mAlpha);
        
        iter++;
    }
}

// -----------------------------------------------------------------------------

const float Meteor::DrawableContainer::Alpha() const
{
    return mAlpha;
}


#pragma mark -
#pragma mark Update/draw cycles
// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::Update( const float deltaTime)
{
    Drawable::Update( deltaTime);
    
    containerType::iterator iter = mChildren.begin();
    
    while ( iter != mChildren.end())
    {
        ( *iter).first->Update( deltaTime);
        
        iter++;
    }
} 

// -----------------------------------------------------------------------------

void Meteor::DrawableContainer::Draw() const
{
    if ( mVisible == false || mChildren.size() == 0)
    {
        return;
    }
    
    glEnable( GL_SCISSOR_TEST);
    
    glScissor( mPosition.X(), mPosition.Y(), mSize.X(), mSize.Y());

    containerType::const_iterator iter = mChildren.begin();
    
    while ( iter != mChildren.end())
    {
        ( *iter).first->Draw();
        
        iter++;
    }
    
    glDisable( GL_SCISSOR_TEST);
}

